<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>电池数据分析-静态加载版</title>
  <!-- 引入Vue.js框架 -->
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
  <!-- 引入ECharts图表库 -->
  <script src="https://cdn.jsdelivr.net/npm/echarts@5.3.2/dist/echarts.min.js"></script>
  <!-- 引入SheetJS库，用于读取Excel文件 -->
  <script src="https://cdn.jsdelivr.net/npm/xlsx@0.17.0/dist/xlsx.full.min.js"></script>
  <!-- <script src="xlsx.full.min.js"></script> -->
  <style>
    /* 设置图表容器的样式 */
    body,
    html {
      margin: 0;
      padding: 0;
      font-family: 'Microsoft YaHei', sans-serif;
      width: 100%;
      height: 100%;
    }

    #app {
      display: flex;
      justify-content: center;
      /* 水平居中 */
      align-items: center;
      /* 垂直居中 */
      width: 100%;
      height: 100vh;
      /* 使用视口高度 */
    }

    /* 添加切换开关的样式 */
    .switch {
      position: relative;
      display: inline-block;
      width: 60px;
      height: 34px;
    }

    .switch input {
      opacity: 0;
      width: 0;
      height: 0;
    }

    .slider {
      position: absolute;
      cursor: pointer;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-color: #ccc;
      transition: .4s;
      border-radius: 34px;
    }

    .slider:before {
      position: absolute;
      content: "";
      height: 26px;
      width: 26px;
      left: 4px;
      bottom: 4px;
      background-color: white;
      transition: .4s;
      border-radius: 50%;
    }

    input.data {
      font-size: 0.5em;
      font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
    }

    input.data:hover {
      cursor: pointer;
    }

    input:checked+.slider {
      background-color: #2196F3;
    }

    input:checked+.slider:before {
      transform: translateX(26px);
    }

    /* 在现有的style标签中添加以下样式 */
    .fancy-button {
      padding: 5px 10px;
      font-size: 12px;
      color: #fff;
      background: linear-gradient(45deg, #2196F3, #00bcd4);
      border: none;
      border-radius: 25px;
      cursor: pointer;
      transition: all 0.3s ease;
      box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
      position: relative;
      overflow: hidden;
    }

    .fancy-button:hover {
      transform: translateY(-2px);
      box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
      background: linear-gradient(45deg, #1976D2, #0097a7);
    }

    .fancy-button:active {
      transform: translateY(0);
      box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
    }

    .fancy-button::after {
      content: '';
      position: absolute;
      top: 50%;
      left: 50%;
      width: 5px;
      height: 5px;
      background: rgba(255, 255, 255, 0.5);
      opacity: 0;
      border-radius: 100%;
      transform: scale(1, 1) translate(-50%);
      transform-origin: 50% 50%;
    }

    .fancy-button:focus:not(:active)::after {
      animation: ripple 1s ease-out;
    }

    @keyframes ripple {
      0% {
        transform: scale(0, 0);
        opacity: 0.5;
      }

      100% {
        transform: scale(100, 100);
        opacity: 0;
      }
    }

    /* 添加标题样式 */
    .title-container {
      position: absolute;
      left: 8%;
      top: 20px;
      z-index: 10;
      background: rgba(255, 255, 255, 0.1);
      padding: 10px 20px;
      border-radius: 8px;
      /* box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); */
      transition: all 0.3s ease;
    }

    .title-text {
      font-size: 18px;
      font-weight: bold;
      font-style: italic;
      color: #2196F3;
      margin: 0;
      user-select: none;
    }

    .title-container:hover {
      transform: translateY(-2px);
      box-shadow: 0 4px 12px rgba(33, 150, 243, 0.2);
    }

    /* 添加等待特效的样式 */
    .loading {
      display: none;
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background-color: rgba(0, 0, 0, 0.5);
      z-index: 9999;
      justify-content: center;
      align-items: center;
    }

    .loading-spinner {
      border: 16px solid #f3f3f3;
      border-top: 16px solid #3498db;
      border-radius: 50%;
      width: 120px;
      height: 120px;
      animation: spin 2s linear infinite;
    }

    @keyframes spin {
      0% {
        transform: rotate(0deg);
      }

      100% {
        transform: rotate(360deg);
      }
    }
  </style>
</head>

<body>
  <!-- Vue应用的根元素 -->
  <div id="app">
    <div class="loading" ref="loading">
      <div class="loading-spinner"></div>
    </div>
    <div class="title-container">
      <h1 class="title-text">TP-BMS电芯测试数据图表分析</h1>
    </div>
    <div style="position: absolute; right: 20%; top: 20px; z-index: 10;" title="切换数据表">
      <!-- <input type="file" ref="fileInput" @change="handleFileSelect" accept=".xlsx;.xls" style="display: none;"> -->
      <input type="file" ref="fileInput" @change="handleFileSelect" accept=".xlsx, .xls" style="display: none;">
      <button @click="$refs.fileInput.click()" class="fancy-button">导入电池测试数据</button>
    </div>
    <!-- 图表将被渲染到这个div中 -->
    <div ref="chart" style="width: 100%; height: 100%;"></div>
  </div>

  <script>
    // 创建Vue实例



    // 创建Vue实例
    new Vue({
      el: '#app',
      data: {
        chart: null, // 用于存储ECharts实例
        excelData: null, // 用于存储从Excel文件读取的数据
        dataType: 'discharge' // 默认选择充电数据表
      },
      mounted() {
        // 组件挂载后不再自动加载数据，等待用户选择文件
      },
      methods: {
        // 处理文件选择事件
        handleFileSelect(event) {
          console.log('开始处理文件，显示等待特效');
          // 显示等待特效
          this.$refs.loading.style.display='flex';

          // 模拟延迟，确保特效有足够的显示时间
          setTimeout(() => {
            const file = event.target.files? event.target.files[0] : null;
            if (!file) {
              console.log('未选择文件，隐藏等待特效');
              // 如果没有选择文件，隐藏等待特效
              this.$refs.loading.style.display='none';
              return;
            }

            // 根据文件名判断数据类型
            if (file.name.toLowerCase().includes('充电')) {
              this.dataType = 'charge';
            } else if (file.name.toLowerCase().includes('放电')) {
              this.dataType = 'discharge';
            }

            const reader = new FileReader();
            reader.onload = (e) => {
              try {
                const data = new Uint8Array(e.target.result);
                const workbook = XLSX.read(data, {
                  type: 'array'
                });
                const firstSheetName = workbook.SheetNames[0];
                const worksheet = workbook.Sheets[firstSheetName];
                this.excelData = XLSX.utils.sheet_to_json(worksheet, {
                  header: 1
                });

                // 过滤掉空行
                this.excelData = this.excelData.filter(row => row.some(cell => cell!== null && cell!== ''));

                this.initChart(); // 初始化图表
              } catch (error) {
                console.error('处理文件数据时出错:', error);
                // 出错时隐藏等待特效
                this.$refs.loading.style.display='none';
              }
            };
            reader.onerror = () => {
              console.error('读取文件出错，隐藏等待特效');
              // 读取文件出错时隐藏等待特效
              this.$refs.loading.style.display='none';
            };
            reader.readAsArrayBuffer(file);
          }, 2000); // 延迟2秒
        },
        // 初始化ECharts图表
        initChart() {
          try {
            this.chart=echarts.init(this.$refs.chart);
            const option=this.getChartOption();
            this.chart.setOption(option);

            console.log('图表初始化完成，隐藏等待特效');
            // 图表初始化完成后隐藏等待特效
            this.$refs.loading.style.display='none';
          } catch(error) {
            console.error('初始化图表时出错:',error);
            // 初始化图表出错时隐藏等待特效
            this.$refs.loading.style.display='none';
          }
        },
        // 获取图表配置选项
        getChartOption() {
          // 获取各列的索引
          const timeColumn=this.excelData[0].indexOf('时间');
          const currentColumn=this.excelData[0].indexOf('电流');
          const socColumn=this.excelData[0].indexOf('SOC');
          const capacityColumn=this.excelData[0].indexOf('剩余容量');
          const voltageColumn=this.excelData[0].indexOf('最大电压');
          const voltageMinColumn=this.excelData[0].indexOf('最小电压');
          const temperatureColumn=this.excelData[0].indexOf('总电压');
         
          // 去掉表头，只保留数据行
          const data=this.excelData.slice(1);
          const totalPoints=data.length; //总行数
          // 如果总数据点少于30，直接使用全部数据点；否则保证至少30个点
          const selectedPoints=totalPoints<30? totalPoints:Math.max(30,Math.floor(totalPoints/100));

          // 计算采样步长
          const step=Math.floor(totalPoints/(selectedPoints-1));

          // 初始化数据数组
          const xAxisData=[];
          const currentData=[];
          const socData=[];
          const capacityData=[];
          const voltageData=[];
          const voltageMinData=[];
          const temperatureData=[];
          // 新增：初始化压差数据数组
          const voltageDiffData=[];

      
// 格式化时间函数
function formatTime(timeValue) {
  if (typeof timeValue === 'string') {
    // 查找时间字符串中第一个空格的位置
    const spaceIndex = timeValue.indexOf(' ');
    if (spaceIndex !== -1) {
      // 截取空格之后的部分，即时分秒
      return timeValue.slice(spaceIndex + 1);
    }
    // 如果没有空格，尝试按 - 分割
    const parts = timeValue.split('-');
    if (parts.length > 3) {
      return parts.slice(3).join(':');
    }
  }
  return timeValue; // 如果格式不正确，返回原始值
}
// 采样数据
          for(let i=0;i<selectedPoints;i++) {
            // 确保最后一个点是数据的最后一行
            const index=i===selectedPoints-1? totalPoints-1:i*step;
            const row=data[index];
            const timeValue=row[timeColumn];
            xAxisData.push(formatTime(timeValue));

            // 处理电流数据
            let currentValue=row[currentColumn];
            if(this.dataType==='discharge') {
              currentValue=currentValue>0? -currentValue:Math.abs(currentValue);
              console.log(currentValue);
            }
            currentData.push(currentValue);

            socData.push(row[socColumn]);
            capacityData.push(row[capacityColumn]);
            voltageData.push(row[voltageColumn]);
            voltageMinData.push(row[voltageMinColumn]);
            temperatureData.push(row[temperatureColumn]);
            // 新增：计算主采样点的压差
            // const voltageDiff=row[voltageColumn]-row[voltageMinColumn];
            // voltageDiffData.push(voltageDiff);

            const voltageDiff=parseFloat((row[voltageColumn]-row[voltageMinColumn])*1000).toFixed(3);
            voltageDiffData.push(voltageDiff);

            // 添加隐藏的小刻度值
            for(let j=1;j<=4;j++) {
              const smallIndex=index+(j*step/5); // 计算小刻度的索引
              if(smallIndex<totalPoints) {
                const smallRow=data[Math.floor(smallIndex)];
                const smallTimeValue=smallRow[timeColumn];
                xAxisData.push(formatTime(smallTimeValue));

                // 处理小刻度的电流数据
                let smallCurrentValue=smallRow[currentColumn];
                if(this.dataType==='discharge') {
                  smallCurrentValue=smallCurrentValue>0? -smallCurrentValue:Math.abs(smallCurrentValue);
                }
                currentData.push(smallCurrentValue);

                socData.push(smallRow[socColumn]);
                capacityData.push(smallRow[capacityColumn]);
                voltageData.push(smallRow[voltageColumn]);
                voltageMinData.push(smallRow[voltageMinColumn]);
                temperatureData.push(smallRow[temperatureColumn]);
                // 新增：计算小刻度采样点的压差
                // const smallVoltageDiff = smallRow[voltageColumn] - smallRow[voltageMinColumn];
                // voltageDiffData.push(smallVoltageDiff);
                // 修改为乘以 1000 并保留三位小数
                const smallVoltageDiff=parseFloat((smallRow[voltageColumn]-smallRow[voltageMinColumn])*1000).toFixed(3);
                voltageDiffData.push(smallVoltageDiff);
              }
            }
          }

          // 返回ECharts配置选项
          return {
            grid: {
              left: '2%',
              right: '10%',
              top: '10%',
              bottom: '5%',
              containLabel: true
            },
            // 配置提示框
            tooltip: {
              trigger: 'axis',
              axisPointer: {
                type: 'cross',
                label: {
                  backgroundColor: '#6a7985'
                }
              },
              formatter: function(params) {
                let result=params[0].axisValue+'<br/>';
                params.forEach(function(item) {
                  let unit='';
                  switch(item.seriesName) {
                    case '电流':
                      unit='A';
                      break;
                    case 'SOC':
                      unit='%';
                      break;
                    case '容量':
                      unit='Ah';
                      break;
                    case '最大电压':
                      unit='V';
                      break;
                    case '最小电压':
                      unit='V';
                    case '总电压':
                      unit='V';
                      break;
                    // 新增：压差单位
                    case '压差':
                      unit='mV';
                      break;
                  }
                  result+=item.marker+item.seriesName+': '+item.value+' '+unit+'<br/>';
                });
                console.log("result",result);
                return result;
              },
            },

            // 配置图例
            legend: {
              data: ['电流','SOC','容量','最大电压','最小电压','总电压','压差'] // 新增：压差图例
            },
            // 配置X轴 横向标题
            xAxis: {
              type: 'category',
              boundaryGap: false,
              data: xAxisData,
              axisLabel: {
                formatter: function(value,index) {
                  // 只显示第一个和最后一个刻度值，其余刻度值每隔一个隐藏三个
                  if(index===0||index===xAxisData.length-1||index%4===0) {
                    return value; // 返回刻度值
                  }
                  return ''; // 隐藏刻度值
                },
                interval: 0,
                rotate: 45,
                textStyle: {
                  fontSize: '0.5em',
                  color: '#333'
                }
              },
              splitLine: {
                show: true,
                lineStyle: {
                  color: 'rgba(0, 0, 0, 0.4)',
                  width: 0.25,
                  type: 'solid'
                }
              },
              axisTick: {
                show: true,
                inside: true
              },
              splitNumber: 5
            },
            // 配置Y轴 右侧刻度标题
            yAxis: [
              {
                type: 'value',
                name: 'Current(A)',
                position: 'left',
                nameGap: 20,
                axisLabel: {
                  textStyle: {
                    color: '#FF0000'
                  },
                  padding: [0,0,0,0]
                },
                splitLine: {
                  show: true,
                  lineStyle: {
                    color: 'rgba(0, 0, 0, 0.5)',
                    width: 0.51,
                    type: 'solid'
                  }
                },
                nameTextStyle: {
                  color: '#FF0000',
                  fontSize: 10
                }
              },
              {
                type: 'value',
                name: 'SOC%',
                position: 'right',
                offset: 25,
                nameGap: 20,
                axisLabel: {
                  textStyle: {
                    color: '#228B22'
                  },
                  padding: [0,0,0,-15]
                },
                splitLine: {
                  show: true,
                  lineStyle: {
                    color: 'rgba(0, 0, 0, 0.2)',
                    width: 0.51,
                    type: 'solid'
                  }
                },
                nameTextStyle: {
                  color: '#228B22',
                  fontSize: 10
                }
              },
              {
                type: 'value',
                name: 'AH',
                position: 'right',
                offset: 75,
                nameGap: 20,
                axisLabel: {
                  textStyle: {
                    color: '#0000FF'
                  },
                  padding: [0,0,0,-15]
                },
                splitLine: {
                  show: true,
                  lineStyle: {
                    color: 'rgba(0, 0, 0, 0.5)',
                    width: 0.51,
                    type: 'solid'
                  }
                },
                nameTextStyle: {
                  color: '#0000FF',
                  fontSize: 10
                }
              },
              {
                type: 'value',
                name: 'MaxV',
                position: 'right',
                offset: 130,
                nameGap: 20,
                max: function(value) {
                  return Math.ceil(value.max);
                },
                axisLabel: {
                  textStyle: {
                    color: 'rgba(255, 140, 0, 1)'
                  },
                  padding: [0,0,0,-15]
                },
                splitLine: {
                  show: true,
                  lineStyle: {
                    color: 'rgba(0, 0, 0, 0.2)',
                    width: 0.51,
                    type: 'solid'
                  }
                },
                nameTextStyle: {
                  color: 'rgba(255, 140, 0, 1)',
                  fontSize: 10
                }
              },
              {
                type: 'value',
                name: 'MinV',
                position: 'right',
                offset: 180,
                nameGap: 20,
                // 调整最大电压值计算方式，确保最小电压曲线显示正确
                max: function (value) {
                  const maxVoltage = Math.max(...voltageData);
                  return Math.ceil(maxVoltage);
                },
                axisLabel: {
                  textStyle: {
                    color: '#1E90FF'
                  },
                  padding: [0,0,0,-15]
                },
                splitLine: {
                  show: true,
                  lineStyle: {
                    color: 'rgba(0, 0, 0, 0.2)',
                    width: 0.51,
                    type: 'solid'
                  }
                },
                nameTextStyle: {
                  color: '#1E90FF',
                  fontSize: 10
                }
              },
              {
                type: 'value',
                name: 'TolV',
                position: 'right',
                offset: 210,
                nameGap: 20,
                axisLabel: {
                  textStyle: {
                    color: '#800080'
                  },
                  padding: [0,0,0,-15]
                },
                splitLine: {
                  show: true,
                  lineStyle: {
                    color: 'rgba(0, 0, 0, 0.5)',
                    width: 0.51,
                    type: 'solid'
                  }
                },
                nameTextStyle: {
                  color: '#800080',
                  fontSize: 10
                }
              },
              // 新增：压差Y轴配置
              {
                type: 'value',
                name: 'MaxΔP(mV)',
                position: 'right',
                offset: 260,
                nameGap: 20,
                axisLabel: {
                  textStyle: {
                    color: '#FF1493'
                  },
                  padding: [0,0,0,-15]
                },
                splitLine: {
                  show: true,
                  lineStyle: {
                    color: 'rgba(0, 0, 0, 0.2)',
                    width: 0.51,
                    type: 'solid'
                  }
                },
                nameTextStyle: {
                  color: '#FF1493',
                  fontSize: 10
                }
              }
            ],
            // 配置数据系列
            series: [
              {
                name: '电流',
                type: 'line',
                data: currentData,
                yAxisIndex: 0,
                itemStyle: {
                  color: '#FF0000'
                },
                lineStyle: {
                  width: 1,
                  type: 'solid'
                },
                symbol: 'circle',
                symbolSize: 3
              },
              {
                name: 'SOC',
                type: 'line',
                data: socData,
                yAxisIndex: 1,
                itemStyle: {
                  color: '#228B22'
                },
                lineStyle: {
                  width: 1,
                  type: 'solid'
                },
                symbol: 'circle',
                symbolSize: 3
              },
              {
                name: '容量',
                type: 'line',
                data: capacityData,
                yAxisIndex: 2,
                itemStyle: {
                  color: '#0000FF'
                },
                lineStyle: {
                  width: 1,
                  type: 'solid'
                },
                symbol: 'circle',
                symbolSize: 3
              },
              {
                name: '最大电压',
                type: 'line',
                data: voltageData,
                yAxisIndex: 3,
                itemStyle: {
                  color: 'rgba(255, 140, 0, 1)'
                },
                lineStyle: {
                  width: 1,
                  type: 'solid'
                },
                symbol: 'circle',
                symbolSize: 3
              },
              {
                name: '最小电压',
                type: 'line',
                data: voltageMinData,
                yAxisIndex: 4,
                itemStyle: {
                  color: '#1E90FF'
                },
                lineStyle: {
                  width: 1,
                  type: 'solid'
                },
                symbol: 'circle',
                symbolSize: 3
              },
              {
                name: '总电压',
                type: 'line',
                data: temperatureData,
                yAxisIndex: 5,
                itemStyle: {
                  color: '#800080'
                },
                lineStyle: {
                  width: 1,
                  type: 'solid'
                },
                symbol: 'circle',
                symbolSize: 3
              },
              // 新增：压差系列配置
              {
                name: '压差',
                type: 'line',
                data: voltageDiffData,
                yAxisIndex: 6,
                itemStyle: {
                  color: '#FF1493'
                },
                lineStyle: {
                  width: 1,
                  type: 'solid'
                },
                symbol: 'circle',
                symbolSize: 3
              }
            ],
            // 添加文本标签显示取样数量
            graphic: [
              {
                type: 'text',
                left: '10%',
                top: 'bottom',
                style: {
                  text: `时间刻度: ${selectedPoints},取样总数: ${selectedPoints*3}, 数据总量: ${totalPoints}`,
                  font: 'bold 12px Microsoft YaHei',
                  fill: '#333'
                }
              },
              {
                type: 'text',
                left: 'right',
                top: 'bottom',
                style: {
                  text: '电池测试数据分析工具V1.0 Wic-power@2025 更新时间: '+new Date().toLocaleString(),
                  font: '12px Microsoft YaHei',
                  fill: '#333'
                }
              }
            ]
          };
        }
      }
    });
  </script>
</body>

</html>